/**
 * @fileOverview game.Tetris
 * @author goodzsq@gmail.com
 */

var BaseClass = gg.module('BaseEntity');

module.exports = gg.createClass({
    attributes: {
        grid: {
            type: 'struct.Grid',
            defaultValue: {i: 10, j: 20, cacheCount: 200},
            setter: function(v) {
                this.grid = v;
            },
            getter: function() {
                return this.grid;
            }
        }
    },
    methods: {
        _cellAutoId: 0,
        _cellTemplate: {ox: 0, oy: 0, active: true, kind: 1},
        _makeCell: function(ox, oy, kind) {
            var t = this._cellTemplate;
            var id = ++this._cellAutoId;
            t.ox = ox;
            t.oy = oy;
            t.kind = kind;
            t.active = true;
            this.grid.addObject(id, t);
            return id;
        },
        _active: [0, 0, 0, 0],
        _cx: 0,
        _cy: 0,
        _makeT: function(kind) {
            switch (kind) {
                case 1:
                    this._active[0] = this._makeCell(-1, 0, kind);
                    this._active[1] = this._makeCell(0, 0, kind);
                    this._active[2] = this._makeCell(1, 0, kind);
                    this._active[3] = this._makeCell(2, 0, kind);
                    this.moveT(4, 0);
                    break;
                case 2:
                    this._active[0] = this._makeCell(0, -1, kind);
                    this._active[1] = this._makeCell(0, 0, kind);
                    this._active[2] = this._makeCell(1, 0, kind);
                    this._active[3] = this._makeCell(2, 0, kind);
                    this.moveT(4, 1);
                    break;
                case 3:
                    this._active[0] = this._makeCell(0, -1, kind);
                    this._active[1] = this._makeCell(-1, 0, kind);
                    this._active[2] = this._makeCell(0, 0, kind);
                    this._active[3] = this._makeCell(1, 0, kind);
                    this.moveT(4, 1);
                    break;
                case 4:
                    this._active[0] = this._makeCell(0, -1, kind);
                    this._active[1] = this._makeCell(-2, 0, kind);
                    this._active[2] = this._makeCell(-1, 0, kind);
                    this._active[3] = this._makeCell(0, 0, kind);
                    this.moveT(4, 1);
                    break;
                case 5:
                    this._active[0] = this._makeCell(-1, 0, kind);
                    this._active[1] = this._makeCell(0, 0, kind);
                    this._active[2] = this._makeCell(0, 1, kind);
                    this._active[3] = this._makeCell(1, 1, kind);
                    this.moveT(4, 0);
                    break;
                case 6:
                    this._active[0] = this._makeCell(-0.5, -0.5, kind);
                    this._active[1] = this._makeCell(0.5, -0.5, kind);
                    this._active[2] = this._makeCell(-0.5, 0.5, kind);
                    this._active[3] = this._makeCell(0.5, 0.5, kind);
                    this.moveT(4.5, 0.5);
                    break;
                case 7:
                    this._active[0] = this._makeCell(0, 0, kind);
                    this._active[1] = this._makeCell(1, 0, kind);
                    this._active[2] = this._makeCell(0, 1, kind);
                    this._active[3] = this._makeCell(-1, 1, kind);
                    this.moveT(4, 0);
                    break;
                default:
                    gg.error('makeT kind error');
            }
        },
        _isEmptyCell: function(i, j) {
            if (!(i >= 0 && i < 10 && j >= 0 && j < 20)) {
                return false;
            }
            var cell = this.grid.getCellObject(i, j);
            if (cell && !cell.active) {
                return false;
            } else {
                return true;
            }
        },
        _canMove: function(x, y) {
            var cell;
            for (var i = 0; i < 4; i++) {
                if (this._active[i]) {
                    cell = this.grid.getObject(this._active[i]);
                    if (!this._isEmptyCell(cell.ox + x, cell.oy + y)) {
                        return false;
                    }
                }
            }
            return true;
        },
        _canRotate: function(dir) {
            var cell, ox, oy;
            for (var i = 0; i < 4; i++) {
                if (this._active[i]) {
                    cell = this.grid.getObject(this._active[i]);
                    if (dir) {
                        ox = -cell.oy;
                        oy = cell.ox;
                    } else {
                        ox = cell.oy;
                        oy = -cell.ox;
                    }
                    if (!this._isEmptyCell(ox + this._cx, oy + this._cy)) {
                        return false;
                    }
                }
            }
            return true;
        },
        moveT: function(x, y) {
            if (!this._canMove(x, y)) {
                console.log('cannot move', x, y);
                return;
            }
            var cell, newi, newj;
            for (var i = 0; i < 4; i++) {
                if (this._active[i]) {
                    cell = this.grid.getObject(this._active[i]);
                    newi = cell.ox + x;
                    newj = cell.oy + y;
                    this.grid.moveObject(this._active[i], newi, newj);
                }
            }
            this._cx = x;
            this._cy = y;
            this.print();
        },
        rotateT: function(dir) {
            if (!this._canRotate(dir)) {
                console.log('cannot rotate');
                return;
            }
            var cell, ox, oy, newi, newj;
            for (var i = 0; i < 4; i++) {
                if (this._active[i]) {
                    cell = this.grid.getObject(this._active[i]);
                    if (dir) {
                        ox = -cell.oy;
                        oy = cell.ox;
                    } else {
                        ox = cell.oy;
                        oy = -cell.ox;
                    }
                    cell.ox = ox;
                    cell.oy = oy;
                    this.grid.moveObject(this._active[i], ox + this._cx, oy + this._cy);
                }
            }
            this.print();
        },
        fallT: function() {
            var x = this._cx;
            var y = this._cy;
            while (this._canMove(x, y)) {
                y += 1;
            }
            this.moveT(x, y - 1);
            for (var i = 0; i < 4; i++) {
                this.grid.setObject(this._active[i], 'active', false);
                this._active[i] = null;
            }
            this.eliminate();
            this._makeT(_.random(1, 7));
        },
        eliminate: function() {
            var r, rows = [];
            for (var j = 0; j < 20; j++) {
                r = this.eliminateRow(j);
                if (r !== false) {
                    rows.push(j);
                }
            }
            if (rows.length > 0) {
                this.trigger('onElimate', this, rows);
                for (var row = 0, max = rows.length; row < max; row++) {
                    this._eraseRow(rows[row]);
                }
            }
        },
        _eraseRow: function(row) {
            for (var j = row - 1; j >= 0; j--) {
                for (var i = 0; i < 10; i++) {
                    var cell = this.grid.getCellObject(i, j, 0);
                    if (cell && !cell.active) {
                        this.grid.moveObject(cell.id, i, j + 1);
                    }
                }
            }
        },
        eliminateRow: function(j) {
            var cell;
            for (var i = 0; i < 10; i++) {
                cell = this.grid.getCellObject(i, j);
                if (cell && !cell.active) {
                    continue;
                } else {
                    return false;
                }
            }
            for (var i = 0; i < 10; i++) {
                var cell = this.grid.getCell(i,j);
                this.grid.killObject.apply(this.grid, cell);
            }
            return true;
        },
        start: function() {
            this._active = [0, 0, 0, 0];
            this.grid.clear();
            this._makeT(_.random(1, 7));
        },
        handleLeft: function() {
            this.moveT(this._cx - 1, this._cy);
        },
        handleRight: function() {
            this.moveT(this._cx + 1, this._cy);
        },
        handleDown: function() {
            this.moveT(this._cx, this._cy + 1);
        },
        handleRotateCW: function() {
            this.rotateT(true);
        },
        handleRotateCCW: function() {
            this.rotateT(false);
        },
        print: function() {
            for (var j = 0; j < 20; j++) {
                var row = '';
                for (var i = 0; i < 10; i++) {
                    var cell = this.grid.getCellObject(i, j);
                    if (cell && cell.kind)
                        row += cell.kind + ' ';
                    else
                        row += '. ';
                }
                console.log(row);
            }
            console.log(this.grid.objectCount);
        }
    },
    events: {
        onEliminate: '消除'
    }
}, BaseClass, [/* trait1, trait2, ... */]);


/** @fileend */

//unittest
UnitTest.add('game.Tetris模块测试',
        function() {
            this.test(true, 'ok');
        }
);